#pragma once

#include <functional>
using namespace std;

namespace qian {

	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{}
		auto_ptr(auto_ptr<T>& sp)
			:_ptr(sp._ptr)
		{
			// 管理权转移
			sp._ptr = nullptr;
		}
		auto_ptr<T>& operator=(auto_ptr<T>& ap)
		{
			// 检测是否为自己给自己赋值
			if (this != &ap)
			{
				// 释放当前对象中资源
				if (_ptr)
					delete _ptr;
				// 转移ap中资源到当前对象中
				_ptr = ap._ptr;
				ap._ptr = NULL;
			}
			return *this;
		}
		~auto_ptr()
		{
			if (_ptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
			}
		}
		// 像指针一样使用
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
		

	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}
		~unique_ptr()
		{
			if (_ptr != nullptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
				_ptr = nullptr;
			}
		}

		//C++98中，delete的意思是不让编译器自动生成默认函数，而C++11为了实现这个智能指针，赋予delete一个新功能：不允许调用
		unique_ptr(auto_ptr<T>& ap) = delete;
		unique_ptr& operator=(auto_ptr<T>& ap) = delete;

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};


	template<class T>
	class shared_ptr {
	public:
		shared_ptr(T* ptr = nullptr)
			: _ptr(ptr)
			,_pcount(new int(1))
		{}

		//定制删除器
		template<class D> //由于这个D是给函数模板用的，而不是给整个类用的
		shared_ptr(T* ptr, D del)
			: _ptr(ptr)
			, _pcount(new int(1))
			, _del(del)
		{}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
		{
			++(*_pcount);
		}

		void release()
		{
			if (--(*_pcount) == 0)
			{
				//delete _ptr; //不能写delete，因为不一定都是new创建出来的
				_del(_ptr); 

				delete _pcount;
				_ptr = nullptr;
				_pcount = nullptr;
			}
		}

		// sp1 = sp3
		// sp3 = sp3
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			//虽然这样显示地写可以避免内存泄露，但是不建议这样用
			//this->~shared_ptr(); 

			if (_ptr != sp._ptr) //避免自己给自己赋值
			{
				release();
				//下面这样写可能会存在会内存泄露，若不调用上面地析构的话
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}

			return *this;
		}

		~shared_ptr()
		{
			/*if (--(*_pcount) == 0)
			{
				delete _ptr;
				delete _pcount;
				_ptr = nullptr;
				_pcount = nullptr;
			}*/

			//换成这样写更时候显示调用析构
			release();
		}


		T* get()
		{
			return _ptr;
		}

		int use_count()
		{
			return *_pcount;
		}

		T& operator*()
		{ 
			return *_ptr; 
		}

		T* operator->()
		{ 
			return _ptr;
		}

	private:
		T* _ptr;
		int* _pcount; //引用计数
		
		//D _del; //因此用不了这个D，这里是可调用对象，那我们就使用包装器来解决
		function<void(T* ptr)> _del = [](T* ptr) {delete ptr; }; //用缺省值来初始化
	};


	template<class T>
	class weak_ptr 
	{
		weak_ptr()
			:_ptr(nullptr)
		{}

		weak_ptr(const shared_ptr <T>& sp)
			:_ptr(sp.get()) //sp的get接口在share_pr中已实现，如上
		{}

		weak_ptr<T>& operator=(const shared_ptr <T>& sp)
		{
			//_ptr = sp._shared_ptr;
			_ptr = sp.get();
			return *this;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
}


